home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-01-02 | 12.5 KB | 519 lines | [TEXT/????] |
- //
- // XBINDING.CPP
- //
- // Copyright (C) Microsoft Corporation, 1996
- //
- // Implements the asynchronous binding model on top of the Netscape plugin
- // APIs.
- //
-
- #include "headers.h"
-
- // Default FORMATETC that is passed to IBindStatusCallback::OnDataAvailable.
- FORMATETC g_NullFormatEtc = {
- CF_NULL,
- NULL,
- DVASPECT_CONTENT,
- -1,
- TYMED_NULL
- };
-
- OLECHAR g_szBSCBHolder[] = "_BSCB_Holder_";
-
- CXBinding::~CXBinding()
- {
- if (m_pbsc != NULL)
- m_pbsc->Release();
- }
-
- //
- // CXBinding::Bind
- //
-
- HRESULT
- CXBinding::Bind(LPOLESTR pszURL, LPBINDSTATUSCALLBACK pbsc, unsigned long BindType)
- {
- HRESULT hr;
- DWORD bindf;
- BINDINFO bindinfo;
- CNetscapeStreamNotify *pBindingNotify;
-
- // Query the client for the type of binding operation they want.
- memset(&bindinfo, 0, sizeof(bindinfo));
- bindinfo.cbSize = sizeof(bindinfo);
- pbsc->GetBindInfo(&bindf, &bindinfo);
-
- // BUGBUG: What exactly are we supposed to do with this?
- if (bindinfo.szExtraInfo != NULL)
- CoTaskMemFree(bindinfo.szExtraInfo);
-
- // Verify that the client is asking for an async, non-blocking, push-data
- // read binding.
- if (!(bindf & BINDF_ASYNCHRONOUS) || !(bindf & BINDF_ASYNCSTORAGE) ||
- ((bindf & BINDF_PULLDATA) && (BindType == TYMED_FILE || BindType == TYMED_FSP))
- || (bindinfo.dwBindVerb != BINDVERB_GET))
- return ResultFromScode(E_FAIL);
-
- // Notify the callback that we're about to start binding.
- hr = pbsc->OnStartBinding(BSCO_ALLONIBSC, (LPBINDING) this);
- if (m_fAborted)
- hr = ResultFromScode(E_ABORT);
-
-
- if (SUCCEEDED(hr))
- {
- // Create the appopriate stream notification object.
- if (BindType == TYMED_FILE || BindType == TYMED_FSP)
- {
- pBindingNotify = new CBindingFileStreamNotify(this, BindType);
- }
- else if(bindf & BINDF_PULLDATA)
- {
- pBindingNotify = new CBindingPullStreamNotify(this);
- }
- else
- {
- pBindingNotify = new CBindingMemoryStreamNotify(this);
- }
-
- if ((pBindingNotify == NULL) ||
- ((pBindingNotify->m_pszURL = OleStrdup(pszURL)) == NULL))
- {
- hr = ResultFromScode(E_OUTOFMEMORY);
- }
- #ifdef PLUGIN_ADAPTER
- else if (NPN_GetURL((NPP) m_pSite->m_ClientInstance,
- pBindingNotify->m_pszURL, NULL) != NPERR_NO_ERROR)
- #elif defined(URLMON_DLL)
- else if (AXGetUrl( pBindingNotify->m_pszURL, pBindingNotify,
- BindType == TYMED_FILE || BindType == TYMED_FSP) != NPERR_NO_ERROR)
- #else
- else if (AXE_GetURL((NPP) m_pSite->m_ClientInstance,
- pBindingNotify->m_pszURL, NULL, pBindingNotify) != NPERR_NO_ERROR)
- #endif
- {
- delete pBindingNotify;
- pBindingNotify = NULL;
- hr = ResultFromScode(E_FAIL);
- } else {
- #ifdef PLUGIN_ADAPTER
- // Link the notification object to the list of objects waiting to
- // be bound.
- pBindingNotify->m_pNextUnattached = m_pSite->m_pUnattachedList;
- m_pSite->m_pUnattachedList = pBindingNotify;
- #endif
-
- m_pbsc = pbsc;
- m_pbsc->AddRef();
-
- // Result indicates that we're in the process of binding, not an error.
- hr = ResultFromScode(E_PENDING);
- }
- }
-
- // If for any reason we're going to return E_PENDING, we need to call
- // OnStopBinding and notify it of the error.
- if (hr != ResultFromScode(E_PENDING)) {
- pbsc->OnStopBinding(hr, NULL);
- }
-
- return hr;
- }
-
- //
- // CXBinding::IUnknown::QueryInterface
- //
- // Returns a pointer to the specified interface on a component to which a
- // client currently holds an interface pointer.
- //
-
- STDMETHODIMP
- CXBinding::QueryInterface(REFIID riid, LPVOID *ppvObj)
- {
- HRESULT hr;
- LPVOID pv;
-
- if (riid == IID_IUnknown || riid == IID_IBinding) {
- pv = (LPVOID)(LPBINDCTX) this;
- ++m_cRef;
- hr = ResultFromScode(S_OK);
- } else {
- pv = NULL;
- hr = ResultFromScode(E_NOINTERFACE);
- }
-
- *ppvObj = pv;
- return hr;
- }
-
- //
- // CXBinding::IUnknown::AddRef
- //
- // Increments the reference count for the calling interface.
- //
-
- STDMETHODIMP_(ULONG)
- CXBinding::AddRef(void)
- {
- return ++m_cRef;
- }
-
- //
- // CXBinding::IUnknown::Release
- //
- // Decrements the reference count for the calling interface on a object. If
- // the reference count on the object falls to zero, the object is freed.
- //
-
- STDMETHODIMP_(ULONG)
- CXBinding::Release(void)
- {
- if (--m_cRef != 0)
- return m_cRef;
-
- delete this;
- return 0;
- }
-
- //
- // CXBinding::IBinding::Abort
- //
- // Permanently aborts the bind operation.
- //
-
- STDMETHODIMP
- CXBinding::Abort(void)
- {
- HRESULT hr;
-
- // The binding operation will be aborted inside the Xxx::OnWrite method.
- // As documented in the "Asynchronous Moniker" spec, the client may
- // continue to receive callback notifications, so we can do this at our
- // earliest convenience.
- if (!m_fAborted) {
- m_fAborted = TRUE;
- hr = ResultFromScode(S_OK);
- } else {
- hr = ResultFromScode(S_FALSE);
- }
-
- return hr;
- }
-
- //
- // CXBinding::IBinding::Suspend
- //
- // Suspends the bind operation until resumed by a call to IBinding::Resume or
- // aborted by a call to IBinding::Abort.
- //
-
- STDMETHODIMP
- CXBinding::Suspend(void)
- {
- // Suspend/resume not supported.
- return ResultFromScode(E_NOTIMPL);
- }
-
- //
- // CXBinding::IBinding::Resume
- //
- // Resumes a binding operation that was suspended by a call to
- // IBinding::Suspend.
- //
-
- STDMETHODIMP
- CXBinding::Resume(void)
- {
- // Suspend/resume not supported.
- return ResultFromScode(E_NOTIMPL);
- }
-
- //
- // CXBinding::IBinding::SetPriority
- //
- // Establishes the priority for the bind operation.
- //
-
- STDMETHODIMP
- CXBinding::SetPriority(LONG nPriority)
- {
- #pragma unused (nPriority)
- // Priority cannot be controlled.
- return ResultFromScode(E_NOTIMPL);
- }
-
- //
- // CXBinding::IBinding::GetPriority
- //
- // Retrieves the current priority of this bind operation.
- //
-
- STDMETHODIMP
- CXBinding::GetPriority(LONG *pnPriority)
- {
- // Priority cannot be controlled.
- *pnPriority = 0; // THREAD_PRIORITY_NORMAL.
- return ResultFromScode(E_NOTIMPL);
- }
-
- //
- // CXBinding::IBinding::GetBindResult
- //
- // Queries the protocol-specific outcome of a bind operation, typically used
- // during IBindStatusCallback::OnStopBinding.
- //
-
- STDMETHODIMP
- CXBinding::GetBindResult(LPCLSID pclsidProtocol, LPDWORD pdwResult, LPOLESTR
- *pszResult, LPDWORD pdwReserved)
- {
- #pragma unused (pclsidProtocol, pdwReserved)
- // We don't have any protocol-specific code, so there's nothing useful to
- // return.
- *pdwResult = 0;
- *pszResult = NULL;
- return ResultFromScode(S_OK);
- }
-
- //
- // CBindingMemoryStreamNotify::OnWrite
- //
- // Extends the default memory stream implementation by notifying the client of
- // data availability.
- //
-
- int32
- CBindingMemoryStreamNotify::OnWrite(NPStream *stream, int32 offset, int32 len,
- void *buffer)
- {
- int32 BytesWritten;
- ULONG BindStatus;
- DWORD fBSCF;
-
- // Tag the stream such that requests for unavailable data made against our
- // IStream return E_PENDING.
- m_fAsyncStreamInProgress = TRUE;
-
- BytesWritten = CMemoryOleStreamNotify::OnWrite(stream, offset, len, buffer);
-
- if (BytesWritten > 0) {
-
- if (!m_fDeliveredFirstNotify) {
- m_fDeliveredFirstNotify = TRUE;
- BindStatus = BINDSTATUS_BEGINDOWNLOADDATA;
- fBSCF = BSCF_FIRSTDATANOTIFICATION;
- } else {
- BindStatus = BINDSTATUS_DOWNLOADINGDATA;
- fBSCF = BSCF_INTERMEDIATEDATANOTIFICATION;
- }
-
- m_pBinding->m_pbsc->OnProgress((ULONG) m_StreamLength,
- (ULONG) m_StreamLength, BindStatus, m_pszURL);
-
- mStorageMedium.tymed = TYMED_ISTREAM;
- mStorageMedium.pstm = (LPSTREAM) this;
- mStorageMedium.pUnkForRelease = (LPUNKNOWN) this;
- AddRef(); // account for mStorageMedium reference
- m_pBinding->m_pbsc->OnDataAvailable(fBSCF, BytesWritten,
- &g_NullFormatEtc, &mStorageMedium);
-
- // If the client called IBinding::Abort, return an error so as to
- // force the stream to terminate.
- if (m_pBinding->m_fAborted)
- BytesWritten = -1;
- }
-
- // If BytesWritten is negative, then the stream will be terminated. The
- // client will be notified of the error in the OnDestroyStream method.
- return BytesWritten;
- }
-
- //
- // CBindingMemoryStreamNotify::OnDestroyStream
- //
- // Extends the default memory stream implementation by notifying the client
- // that the binding operation is complete.
- //
-
- NPError
- CBindingMemoryStreamNotify::OnDestroyStream(NPStream *stream, NPError reason)
- {
- #pragma unused (stream)
- HRESULT hr;
-
- m_fAsyncStreamInProgress = FALSE;
-
- // You would think Netscape would pass the right reason code to us, but it
- // always returns a zero on success, so maybe they want NPERR_NO_ERROR???
- if ((reason == NPERR_NO_ERROR || reason == NPRES_DONE) &&
- !m_pBinding->m_fAborted) {
- // Send the final progress notification.
- m_pBinding->m_pbsc->OnProgress((ULONG) m_StreamLength,
- (ULONG) m_StreamLength, BINDSTATUS_ENDDOWNLOADDATA, m_pszURL);
-
- // Although the data stream hasn't changed, we need to send the last
- // data notification.
- mStorageMedium.tymed = TYMED_ISTREAM;
- mStorageMedium.pstm = (LPSTREAM) this;
- mStorageMedium.pUnkForRelease = (LPUNKNOWN) this;
- m_pBinding->m_pbsc->OnDataAvailable(BSCF_LASTDATANOTIFICATION,
- m_StreamLength, &g_NullFormatEtc, &mStorageMedium);
-
- hr = ResultFromScode(S_OK);
- } else {
- hr = ResultFromScode(E_ABORT);
- }
-
- // Notify the callback that the binding has stopped. Plus, we're through
- // with the binding object, so we're ready to throw it away. The client
- // is supposed to release the pointer in the OnStopBinding method, so we'll
- // make sure we don't leak anything by just deleting the binding.
- m_pBinding->m_pbsc->OnStopBinding(hr, NULL);
- delete m_pBinding;
- m_pBinding = NULL;
-
- // We're through with this binding callback object. The user may be
- // holding on to our stream object though, so we must pay attention to our
- // reference count.
- this->Release();
-
- return NPERR_NO_ERROR;
- }
-
- //
- // CBindingFileStreamNotify::IUnknown::QueryInterface
- //
-
- STDMETHODIMP
- CBindingFileStreamNotify::QueryInterface(REFIID riid, LPVOID *ppvObj)
- {
- HRESULT hr;
- LPVOID pv;
-
- if (riid == IID_IUnknown) {
- pv = (LPVOID)(LPUNKNOWN) this;
- ++m_cRef;
- hr = ResultFromScode(S_OK);
- } else {
- pv = NULL;
- hr = ResultFromScode(E_NOINTERFACE);
- }
-
- *ppvObj = pv;
- return hr;
- }
-
- //
- // CBindingFileStreamNotify::IUnknown::AddRef
- //
-
- STDMETHODIMP_(ULONG)
- CBindingFileStreamNotify::AddRef(void)
- {
- return ++m_cRef;
- }
-
- //
- // CBindingFileStreamNotify::IUnknown::Release
- //
-
- STDMETHODIMP_(ULONG)
- CBindingFileStreamNotify::Release(void)
- {
- if (--m_cRef != 0)
- return m_cRef;
-
- delete this;
- return 0;
- }
-
- //
- // CBindingFileStreamNotify::OnNewStream
- //
-
- NPError
- CBindingFileStreamNotify::OnNewStream(NPMIMEType type, NPStream *stream, NPBool
- seekable, uint16 *stype)
- {
- #pragma unused (type, stream, seekable)
- // REVIEW: We're not sending any notifications to the client, but there's
- // not much useful information that we can provide. The client initiated
- // the download, so they probably don't want to abort at the very start of
- // the process. The next notification we get back from the browser is the
- // filename of the data, so we there's nothing to abort.
- *stype = NP_ASFILE;
- return NPERR_NO_ERROR;
- }
-
- //
- // CBindingFileStreamNotify::OnStreamAsFile
- //
-
- void
- CBindingFileStreamNotify::OnStreamAsFile(NPStream *stream, const char* fname)
- {
- #pragma unused (stream)
- HRESULT hr = S_OK;
-
- if (fname != NULL)
- {
- // Note that we pass ourselves as the IUnknown that will release this
- // resource. Default behavior for the TYMED_FILENAME type is to
- // delete the file, but we want to keep it around in the cache. Plus,
- // we may want to do something more in the future. The filename is
- // always released by the client (see ReleaseStgMedium).
- mStorageMedium.tymed = mBindType;
- mStorageMedium.pUnkForRelease = (LPUNKNOWN) this;
- if(mBindType == TYMED_FILE)
- {
- mStorageMedium.lpszFileName = OleStrdup(fname);
- if(mStorageMedium.lpszFileName == NULL)
- hr = E_OUTOFMEMORY;
- }
- else if(mBindType == TYMED_FSP)
- {
- mStorageMedium.pFSSpec = (FSSpec*)CoTaskMemAlloc(sizeof(FSSpec));
- if(mStorageMedium.pFSSpec == NULL)
- hr = E_OUTOFMEMORY;
- else
- {
- Str255 FileName;
-
- FileName[0] = strlen(fname);
- strncpy((char*)&FileName[1], fname, FileName[0]);
- FSMakeFSSpec(0, 0, FileName, mStorageMedium.pFSSpec);
- }
- }
- if (hr == S_OK)
- {
- ++m_cRef; // Account for 'mStorageMedium' reference
- m_pBinding->m_pbsc->OnDataAvailable(BSCF_LASTDATANOTIFICATION, 0,
- &g_NullFormatEtc, &mStorageMedium);
- }
- } else {
- hr = E_FAIL;
- }
-
- // Notify the callback that the binding has stopped. Plus, we're through
- // with the binding object, so we're ready to throw it away. The client
- // is supposed to release the pointer in the OnStopBinding method, so we'll
- // make sure we don't leak anything by just deleting the binding.
- m_pBinding->m_pbsc->OnStopBinding(hr, NULL);
- delete m_pBinding;
- m_pBinding = NULL;
- }
-
- //
- // CBindingFileStreamNotify::OnDestroyStream
- //
-
- NPError
- CBindingFileStreamNotify::OnDestroyStream(NPStream *stream, NPError reason)
- {
- #pragma unused (stream, reason)
- // The client may still have a reference to our object from the STGMEDIUM
- // structure.
- this->Release();
- return NPERR_NO_ERROR;
- }
-